﻿using Grand.Business.Checkout.Services.GiftVouchers;
using Grand.Business.Core.Interfaces.Checkout.GiftVouchers;
using Grand.Data;
using Grand.Domain.Orders;
using Grand.Infrastructure.Events;
using MediatR;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Grand.Business.Checkout.Tests.Services.GiftVouchers;

[TestClass]
public class GiftVoucherServiceTests
{
    private Mock<IMediator> _mediatorMock;
    private Mock<IRepository<GiftVoucher>> _repositoryMock;
    private IGiftVoucherService _service;

    [TestInitialize]
    public void Init()
    {
        _repositoryMock = new Mock<IRepository<GiftVoucher>>();
        _mediatorMock = new Mock<IMediator>();
        _service = new GiftVoucherService(_repositoryMock.Object, _mediatorMock.Object);
    }

    [TestMethod]
    public void GenerateGiftVoucherCode_ShouldReturnUniqueValues()
    {
        var results = new List<string>();
        results.Add(_service.GenerateGiftVoucherCode());
        results.Add(_service.GenerateGiftVoucherCode());
        results.Add(_service.GenerateGiftVoucherCode());
        results.Add(_service.GenerateGiftVoucherCode());
        results.Add(_service.GenerateGiftVoucherCode());
        results.Add(_service.GenerateGiftVoucherCode());
        results.Add(_service.GenerateGiftVoucherCode());

        Assert.IsTrue(results.Count.Equals(results.Distinct().Count()));
    }

    [TestMethod]
    public async Task InsertGiftVoucher_InovokeExpectedMethods()
    {
        await _service.InsertGiftVoucher(new GiftVoucher { Code = "code" });
        _repositoryMock.Verify(c => c.InsertAsync(It.IsAny<GiftVoucher>()), Times.Once);
        _mediatorMock.Verify(c => c.Publish(It.IsAny<EntityInserted<GiftVoucher>>(), default), Times.Once);
    }

    [TestMethod]
    public void InsertGiftVoucher_NullArgument_ThrowException()
    {
        Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await _service.InsertGiftVoucher(null));
    }

    [TestMethod]
    public async Task UpdateGiftVoucher_InovokeExpectedMethods()
    {
        await _service.UpdateGiftVoucher(new GiftVoucher { Code = "code" });
        _repositoryMock.Verify(c => c.UpdateAsync(It.IsAny<GiftVoucher>()), Times.Once);
        _mediatorMock.Verify(c => c.Publish(It.IsAny<EntityUpdated<GiftVoucher>>(), default), Times.Once);
    }

    [TestMethod]
    public void UpdateGiftVoucher_NullArgument_ThrowException()
    {
        Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await _service.UpdateGiftVoucher(null));
    }

    [TestMethod]
    public async Task DeleteGiftVoucher_InovokeExpectedMethods()
    {
        await _service.DeleteGiftVoucher(new GiftVoucher());
        _repositoryMock.Verify(c => c.DeleteAsync(It.IsAny<GiftVoucher>()), Times.Once);
        _mediatorMock.Verify(c => c.Publish(It.IsAny<EntityDeleted<GiftVoucher>>(), default), Times.Once);
    }

    [TestMethod]
    public void DeleteGiftVoucher_NullArgument_ThrowException()
    {
        Assert.ThrowsExceptionAsync<ArgumentNullException>(async () => await _service.DeleteGiftVoucher(null));
    }
}